#include "dicom/upload/resume_info.h"

namespace dicom {

Status ResumeInfoDb::OpenDb(const std::string& path) {
  Status s = db::Database::Open(path, &db_);
  if (!s.ok()) {
    return s;
  }
  return CreateTableIfNotExists();
}

void ResumeInfoDb::DeleteResumeInfo(const std::string& fid,
                                    const std::string& src_md5) {
  LockGuard g(mu_);
  const char* sql = "delete from resume_info where fid = ? and src_md5 = ?";
  db::StmtPtr stmt = db_->Prepare(sql);
  stmt->BindText(fid);
  stmt->BindText(src_md5);
  stmt->Step();
}

bool ResumeInfoDb::LoadResumeInfo(db::StmtPtr& stmt, ResumeInfo* info) {
  int pos = 0;
  info->fid = stmt->GetText(pos++);
  info->src_md5 = stmt->GetText(pos++);
  info->location = stmt->GetText(pos++);
  info->offset = stmt->GetInt64(pos++);
  info->failed_count = stmt->GetInt32(pos++);
  info->insert_at = Timestamp(stmt->GetInt64(pos++));
  return true;
}

bool ResumeInfoDb::GetResumeInfo(const std::string& fid,
                                 const std::string& src_md5, ResumeInfo* info) {
  LockGuard g(mu_);
  const char* sql =
      "select "
      "fid, "
      "src_md5, location, offset, failed_count, insert_at "
      "from resume_info "
      "where fid = ? and src_md5 = ?";

  db::StmtPtr stmt = db_->Prepare(sql);
  stmt->BindText(fid);
  stmt->BindText(src_md5);
  stmt->Step();
  if (stmt->eof()) {
    return false;
  }

  LoadResumeInfo(stmt, info);
  return true;
}

void ResumeInfoDb::UpdateResumeInfo(const ResumeInfo* info) {
  LockGuard g(mu_);
  const char* sql =
      "replace into resume_info( "
      "fid, "
      "src_md5, "
      "location, "
      "offset, "
      "failed_count, "
      "insert_at) values "
      "(?, ?, ?, ?, ?, ?)";

  db::StmtPtr stmt = db_->Prepare(sql);
  stmt->BindText(info->fid);
  stmt->BindText(info->src_md5);
  stmt->BindText(info->location);
  stmt->BindInt64(info->offset);
  stmt->BindInt32(info->failed_count);
  stmt->BindInt64(info->insert_at.MicroSecondsSinceEpoch());
  stmt->Step();
}

Status ResumeInfoDb::CreateTableIfNotExists() {
  const char* sql =
      "create table if not exists resume_info ( "
      "fid varchar not null, "
      "src_md5 varchar not null, "
      "location varchar not null, "
      "offset integer default 0, "
      "failed_count integer default 0, "
      "insert_at integer default 0, "
      "primary key(fid, src_md5)"
      ")";

  db_->RunSql(sql);
  return Status();
}
}
